import chardet
import logging

log = logging.getLogger(__name__)



class StepStringReplace:
    Quotation = 39
    NumberSign = 35
    SearchMode = 0
    RecordMode = 1
    EscapeMode = 2
    KeepMode = 3
    End = 36
    LEGAL_MAX = 2147483647
    ILLEGAL_REPLACE = b'2147483647'
    def __init__(self):
        # {newUUid: replaced}
        self.backReplacedMap = {}
        # {replaced: newUUid}
        self.replacedMap = {}
        self.toCheckEncoding = b''
        self.count = 0
        self.encode = ''
        self.clearIllegalFlag()

    def getBackReplaced(self, key):
        try:
            realKey = key.encode()
            if(realKey in self.backReplacedMap):
                return self.backReplacedMap[realKey].decode(self.encode)
        except Exception as e:
            return None


    def checkEncoding(self):
        result = None
        logging.debug('checkEncoding:', )
        if(self.count > 3):
            result = chardet.detect(self.toCheckEncoding)
        elif(self.count > 1):
            result = chardet.detect(self.toCheckEncoding + self.toCheckEncoding)
        else:
            result = chardet.detect(self.toCheckEncoding + self.toCheckEncoding + self.toCheckEncoding + self.toCheckEncoding)
        if 'encoding' in result:
            self.encode = 'latin-1' if not result['encoding'] else result['encoding']
        else:
            self.encode = 'latin-1'
    def replaceStepFile(self, inFile, outFile):
        with open(inFile, 'rb') as f:
            buf = f.read()
            outBuf = self.feed(buf)
            with open(outFile, 'wb') as fw:
                fw.write(outBuf)

    def appendStr2List(self, inStr, li):
        for ch in inStr:
            li.append(ch)
        li.append(self.End)

    def getNewUuid(self):
        self.count = self.count + 1
        return str(self.count).encode('ascii')

    def checkIsNumber(self, ch):
        return ch > 47 and ch < 58

    def getIntFromBin(self, num):
        s = ''
        for i in num:
            c = i - 48
            s = s + str(c)
        return int(s)
    def checkIllegal(self, ch):
        if(self.illegalMode == self.SearchMode):
            if(ch == self.NumberSign):
                self.illegalCount = ''
                self.toReplaceIllegal = ''
                self.illegalMode = self.RecordMode
        elif(self.illegalMode == self.RecordMode):
            if(self.checkIsNumber(ch)):
                self.toReplaceIllegal = self.toReplaceIllegal + str(ch-48)
                self.illegalCount = self.illegalCount + str(ch - 48)
                if(int(self.illegalCount) > self.LEGAL_MAX):
                    self.illegalMode = self.KeepMode
            else:
                self.clearIllegalFlag()
        else:
            if(self.checkIsNumber(ch)):
                self.toReplaceIllegal = self.toReplaceIllegal + str(ch-48)
            else:
                self.illegalMode = self.SearchMode
                return True
        return False


    def clearIllegalFlag(self):
        self.illegalCount = ''
        self.toReplaceIllegal = ''
        self.illegalMode = self.SearchMode

    def replaceIllegalToken(self, obj):
        last = obj.pop()
        obj = obj[0: -len(self.toReplaceIllegal)]
        obj.extend(self.ILLEGAL_REPLACE)
        obj.append(last)
        return obj

    def feed(self, inStr):
        '''inStr must be a binary string, or a encoded string'''
        result = []
        toReplace = []
        mode = self.SearchMode
        length = len(inStr)
        isReplace = False
        for index in range(length):
            ch = inStr[index]
            if(mode == self.SearchMode):
                result.append(ch)
                #if(self.checkIllegal(ch)):
                #    result = self.replaceIllegalToken(result)

                if(ch == self.Quotation):
                    self.clearIllegalFlag()
                    mode = self.RecordMode
                    toReplace = []
            elif(mode == self.RecordMode):
                if(ch > 127):
                    isReplace = True
                if(ch == self.Quotation):
                    if(index == length - 1):
                        if(isReplace):
                            replacedStr = bytes(toReplace)
                            if replacedStr in self.replacedMap:
                                uuid = self.replacedMap[replacedStr]
                                self.appendStr2List(uuid, result)
                            else:
                                self.toCheckEncoding += replacedStr
                                uuid = self.getNewUuid()
                                self.replacedMap[replacedStr] = uuid
                                self.backReplacedMap[uuid] = replacedStr
                                self.appendStr2List(uuid, result)
                            isReplace = False
                        else:
                            result.extend(toReplace)
                        result.append(self.Quotation)
                        mode = self.SearchMode
                    elif (inStr[index + 1] == self.Quotation):
                        toReplace.append(self.Quotation)
                        #需要填补单引号
                        toReplace.append(self.Quotation)
                        mode = self.EscapeMode
                    else:
                        if(isReplace):
                            replacedStr = bytes(toReplace)
                            if replacedStr in self.replacedMap:
                                uuid = self.replacedMap[replacedStr]
                                self.appendStr2List(uuid, result)
                            else:
                                self.toCheckEncoding += replacedStr
                                uuid = self.getNewUuid()
                                self.replacedMap[replacedStr] = uuid
                                self.backReplacedMap[uuid] = replacedStr
                                self.appendStr2List(uuid, result)
                        else:
                            result.extend(toReplace)
                        result.append(self.Quotation)
                        isReplace = False
                        mode = self.SearchMode
                else:
                    toReplace.append(ch)
            else:
                #in escape mode
                mode = self.RecordMode
        self.checkEncoding()

        return bytes(result)

if __name__ == '__main__':
    import sys
    rep = StepStringReplace()
    #strOut = rep.feed(sys.argv[1].encode())
    #print('strOut:', strOut)
    rep.replaceStepFile(sys.argv[1], sys.argv[2])
    print('encoding:')
    print(rep.encode)
    #print('replacedMap:')
    #print(rep.replacedMap)
    print('backReplacedMap:')
    for key in rep.backReplacedMap:
        print(key, ':', rep.backReplacedMap[key].decode(rep.encode))

